using Moq;
using NUnit.Framework;
using Tycho.Parser.Peg;

namespace Tycho.Parser.Tests.Peg {
    [TestFixture]
    public class EndBlockProductionSpecification {
        [Test]
        public void ShouldParseCloseBracket() {
            var source = " }";

            var result = new EndBlockProduction (new Mock<IMemoClearer> ().Object).Parse (source, 0, new ParseContext () {BracketDepth = 1});

            Assert.IsNotNull (result);
            Assert.AreEqual ("}", ((KeywordTerm) result.Term).Name);
            Assert.AreEqual (0, result.Context.BracketDepth);
            Assert.AreEqual (2, result.Index);
            Assert.AreEqual (new SourceInformation (null, 1, 1), result.Term.SourceInformation);
        }

        [Test]
        public void ShouldParseUnindentedNewLine() {
            var source = " \n  id";

            var result = new EndBlockProduction (new Mock<IMemoClearer> ().Object).Parse (source, 0, new ParseContext () {LastIndent = "    "});

            Assert.IsNotNull (result);
            Assert.AreEqual ("}", ((KeywordTerm) result.Term).Name);
            Assert.AreEqual ("  ", result.Context.LastIndent);
            Assert.AreEqual (1, result.Index);
            Assert.AreEqual (new SourceInformation (null, 1, 3), result.Term.SourceInformation);
        }

        [Test]
        public void ShouldParseNewLineFollowedByEndOfSource() {
            var source = " \n  ";

            var result = new EndBlockProduction (new Mock<IMemoClearer> ().Object).Parse (source, 0, new ParseContext () {LastIndent = "    "});

            Assert.IsNotNull (result);
            Assert.AreEqual ("}", ((KeywordTerm) result.Term).Name);
            Assert.AreEqual (null, result.Context.LastIndent);
            Assert.AreEqual (1, result.Index);
            Assert.AreEqual (new SourceInformation (null, 1, 3), result.Term.SourceInformation);
        }

        [Test]
        public void ShouldParseEndOfSource () {
            var source = "";

            var result = new EndBlockProduction (new Mock<IMemoClearer> ().Object).Parse (source, 0, new ParseContext () {LastIndent = "    "});

            Assert.IsNotNull (result);
            Assert.AreEqual ("}", ((KeywordTerm) result.Term).Name);
            Assert.AreEqual (null, result.Context.LastIndent);
            Assert.AreEqual (0, result.Index);
            Assert.AreEqual (new SourceInformation (null, 0, 0), result.Term.SourceInformation);
        }

        [Test]
        public void ShouldNotParseEndOfSourceIfLastIndentIsNull () {
            var source = "";

            var result = new EndBlockProduction (new Mock<IMemoClearer> ().Object).Parse (source, 0, new ParseContext () {LastIndent = null});

            Assert.IsNull (result);
        }

        [Test]
        public void ShouldNotParseEndOfSourceIfLastIndentIsEmpty () {
            var source = "";

            var result = new EndBlockProduction (new Mock<IMemoClearer> ().Object).Parse (source, 0, new ParseContext () {LastIndent = ""});

            Assert.IsNull (result);
        }

        [Test]
        public void ShouldNotParseEndOfSourceIfBracketDepthGreaterThanZero () {
            var source = "";

            var result = new EndBlockProduction (new Mock<IMemoClearer> ().Object).Parse (source, 0, new ParseContext () {LastIndent = "", BracketDepth = 1});

            Assert.IsNull (result);
        }

        [Test]
        public void ShouldClearResultOnStatementDelimiterWhenReturningSameIndex () {
            var sourceString = " \n  id";

            var memoClearer = new Mock<IMemoClearer> ();

            var context = new ParseContext () { LastIndent = "    " };
            var terminal = new EndBlockProduction (memoClearer.Object);

            var environment = new ParseEnvironment ("filename");
            char[] source = sourceString.ToCharArray();
            var result = terminal.Parse (source, 1, context, sourceString, environment);

            Assert.IsNotNull (result);
            Assert.AreEqual ("}", ((KeywordTerm) result.Term).Name);
            Assert.AreEqual ("  ", result.Context.LastIndent);
            Assert.AreEqual (1, result.Index);
            Assert.AreEqual (new SourceInformation ("filename", 1, 3), result.Term.SourceInformation);

            memoClearer.Verify (m => m.ClearMemoFor (1, source));
        }

        [Test]
        public void ShouldNotParseUnindentedNewLineIfBracketDepthIsGreaterThanZero() {
            var source = " \n    id";

            var result = new EndBlockProduction (new Mock<IMemoClearer> ().Object).Parse (source, 0, new ParseContext () {BracketDepth = 1, LastIndent = "      "});

            Assert.IsNull (result);
        }

        [Test]
        public void ShouldNotParseAnythingElse() {
            var source = " id";

            var result = new EndBlockProduction (new Mock<IMemoClearer> ().Object).Parse (source, 0, new ParseContext ());

            Assert.IsNull (result);
        }
    }
}